package com.kurt.service.impl;

import com.kurt.dto.MenuDTO;
import com.kurt.dto.create.MenuCreateRequest;
import com.kurt.dto.query.MenuQueryRequest;
import com.kurt.dto.update.MenuUpdateRequest;
import com.kurt.entity.SysMenu;
import com.kurt.repository.SysMenuRepository;
import com.kurt.repository.SysRoleMenuRepository;
import com.kurt.repository.SysUserRoleRepository;
import com.kurt.service.MenuService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 菜单服务实现类
 * 实现菜单相关的业务逻辑
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MenuServiceImpl extends BaseServiceImpl<SysMenu, Long> implements MenuService {

    private final SysMenuRepository menuRepository;
    private final SysRoleMenuRepository roleMenuRepository;
    private final SysUserRoleRepository userRoleRepository;

    @Override
    protected SysMenuRepository getRepository() {
        return menuRepository;
    }

    @Override
    protected SysMenuRepository getSpecificationExecutor() {
        return menuRepository;
    }

    @Override
    @Transactional
    public MenuDTO createMenu(MenuCreateRequest createRequest) {
        log.info("创建菜单: {}", createRequest.getName());

        // 检查菜单名称是否已存在
        if (menuRepository.findByName(createRequest.getName()).isPresent()) {
            throw new RuntimeException("菜单名称已存在");
        }

        // 检查菜单编码是否已存在
        if (menuRepository.findByCode(createRequest.getCode()).isPresent()) {
            throw new RuntimeException("菜单编码已存在");
        }

        // 创建菜单实体
        SysMenu menu = new SysMenu();
        BeanUtils.copyProperties(createRequest, menu);
        menu.setCreateTime(LocalDateTime.now());
        menu.setUpdateTime(LocalDateTime.now());

        // 计算菜单层级
        if (createRequest.getParentId() != null && createRequest.getParentId() > 0) {
            // 这里可以根据需要计算层级，暂时简化处理
            menu.setLevel(1); // 简化处理，实际应该根据父菜单层级计算
        } else {
            menu.setLevel(1);
        }

        // 保存菜单
        menu = menuRepository.save(menu);

        log.info("菜单创建成功: {}", menu.getName());
        return convertToMenuDTO(menu);
    }

    @Override
    @Transactional
    public MenuDTO updateMenu(MenuUpdateRequest updateRequest) {
        log.info("更新菜单: {}", updateRequest.getId());

        // 查找菜单
        SysMenu menu = getById(updateRequest.getId());

        // 检查菜单名称是否已存在（排除自己）
        if (StringUtils.hasText(updateRequest.getName()) &&
                !updateRequest.getName().equals(menu.getName()) &&
                menuRepository.findByName(updateRequest.getName()).isPresent()) {
            throw new RuntimeException("菜单名称已存在");
        }

        // 检查菜单编码是否已存在（排除自己）
        if (StringUtils.hasText(updateRequest.getCode()) &&
                !updateRequest.getCode().equals(menu.getCode()) &&
                menuRepository.findByCode(updateRequest.getCode()).isPresent()) {
            throw new RuntimeException("菜单编码已存在");
        }

        // 更新菜单信息
        if (StringUtils.hasText(updateRequest.getName())) {
            menu.setName(updateRequest.getName());
        }
        if (StringUtils.hasText(updateRequest.getCode())) {
            menu.setCode(updateRequest.getCode());
        }
        if (updateRequest.getParentId() != null) {
            menu.setParentId(updateRequest.getParentId());
        }
        if (updateRequest.getType() != null) {
            menu.setType(updateRequest.getType());
        }
        if (StringUtils.hasText(updateRequest.getPath())) {
            menu.setPath(updateRequest.getPath());
        }
        if (StringUtils.hasText(updateRequest.getComponent())) {
            menu.setComponent(updateRequest.getComponent());
        }
        if (StringUtils.hasText(updateRequest.getIcon())) {
            menu.setIcon(updateRequest.getIcon());
        }
        if (updateRequest.getSortOrder() != null) {
            menu.setSortOrder(updateRequest.getSortOrder());
        }
        if (updateRequest.getStatus() != null) {
            menu.setStatus(updateRequest.getStatus());
        }
        if (updateRequest.getHidden() != null) {
            menu.setHidden(updateRequest.getHidden());
        }
        if (updateRequest.getCache() != null) {
            menu.setCache(updateRequest.getCache());
        }
        if (StringUtils.hasText(updateRequest.getPermission())) {
            menu.setPermission(updateRequest.getPermission());
        }
        if (StringUtils.hasText(updateRequest.getRemark())) {
            menu.setRemark(updateRequest.getRemark());
        }
        menu.setUpdateTime(LocalDateTime.now());

        // 保存菜单
        menu = menuRepository.save(menu);

        log.info("菜单更新成功: {}", menu.getName());
        return convertToMenuDTO(menu);
    }

    @Override
    public MenuDTO getMenuById(Long id) {
        SysMenu menu = getById(id);
        return convertToMenuDTO(menu);
    }

    @Override
    public Page<MenuDTO> getMenuPage(MenuQueryRequest queryRequest) {
        // 构建分页参数
        Sort sort = Sort.by(Sort.Direction.fromString(queryRequest.getOrderDirection()), queryRequest.getOrderBy());
        Pageable pageable = PageRequest.of(queryRequest.getPageNum() - 1, queryRequest.getPageSize(), sort);

        // 构建查询条件
        Specification<SysMenu> spec = buildMenuSpecification(queryRequest);

        // 执行分页查询
        Page<SysMenu> menuPage = menuRepository.findAll(spec, pageable);

        // 转换为DTO
        return menuPage.map(this::convertToMenuDTO);
    }

    @Override
    public List<MenuDTO> getMenuList(MenuQueryRequest queryRequest) {
        // 构建查询条件
        Specification<SysMenu> spec = buildMenuSpecification(queryRequest);

        // 执行查询
        List<SysMenu> menus = menuRepository.findAll(spec);

        // 转换为DTO
        return menus.stream().map(this::convertToMenuDTO).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public boolean deleteMenu(Long id) {
        log.info("删除菜单: {}", id);

        // 检查是否有子菜单
        List<SysMenu> children = menuRepository.findByParentId(id);
        if (!children.isEmpty()) {
            throw new RuntimeException("该菜单下还有子菜单，无法删除");
        }

        // 删除角色菜单关联
        roleMenuRepository.deleteByMenuId(id);

        // 删除菜单
        menuRepository.deleteById(id);

        log.info("菜单删除成功: {}", id);
        return true;
    }

    @Override
    @Transactional
    public boolean deleteMenus(List<Long> ids) {
        log.info("批量删除菜单: {}", ids);

        for (Long id : ids) {
            deleteMenu(id);
        }

        log.info("批量删除菜单成功: {}", ids);
        return true;
    }

    @Override
    public List<MenuDTO> getMenuTree(Long parentId) {
        // 获取指定父ID下的直接子菜单
        List<SysMenu> menus = menuRepository.findByParentIdAndStatusOrderBySortOrderAsc(parentId, 1);

        // 转换为DTO并递归构建子菜单
        return menus.stream()
                .map(menu -> {
                    MenuDTO menuDTO = convertToMenuDTO(menu);
                    // 递归获取子菜单
                    List<MenuDTO> children = getMenuTree(menu.getId());
                    menuDTO.setChildren(children);
                    return menuDTO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<MenuDTO> getAllMenuTree() {
        return getMenuTree(0L);
    }

    @Override
    public List<MenuDTO> getChildrenByParentId(Long parentId) {
        List<SysMenu> menus = menuRepository.findByParentId(parentId);
        return menus.stream().map(this::convertToMenuDTO).collect(Collectors.toList());
    }

    @Override
    public List<MenuDTO> getMenusByUserId(Long userId) {
        List<SysMenu> menus = menuRepository.findByUserId(userId);
        return menus.stream().map(this::convertToMenuDTO).collect(Collectors.toList());
    }

    @Override
    public List<MenuDTO> getMenusByRoleId(Long roleId) {
        List<SysMenu> menus = menuRepository.findByRoleId(roleId);
        return menus.stream().map(this::convertToMenuDTO).collect(Collectors.toList());
    }

    @Override
    public boolean existsByName(String name) {
        return menuRepository.findByName(name).isPresent();
    }

    @Override
    public boolean existsByNameAndIdNot(String name, Long excludeId) {
        return menuRepository.findByNameAndIdNot(name, excludeId).isPresent();
    }

    @Override
    public boolean existsByCode(String code) {
        return menuRepository.findByCode(code).isPresent();
    }

    @Override
    public boolean existsByCodeAndIdNot(String code, Long excludeId) {
        return menuRepository.findByCodeAndIdNot(code, excludeId).isPresent();
    }

    @Override
    @Transactional
    public boolean updateStatus(Long id, Integer status) {
        log.info("更新菜单状态: id={}, status={}", id, status);

        SysMenu menu = getById(id);
        menu.setStatus(status);
        menu.setUpdateTime(LocalDateTime.now());
        menuRepository.save(menu);

        log.info("菜单状态更新成功: id={}, status={}", id, status);
        return true;
    }

    @Override
    @Transactional
    public boolean updateSortOrder(Long id, Integer sortOrder) {
        log.info("更新菜单排序: id={}, sortOrder={}", id, sortOrder);

        SysMenu menu = getById(id);
        menu.setSortOrder(sortOrder);
        menu.setUpdateTime(LocalDateTime.now());
        menuRepository.save(menu);

        log.info("菜单排序更新成功: id={}, sortOrder={}", id, sortOrder);
        return true;
    }

    @Override
    @Transactional
    public boolean moveMenu(Long id, Long newParentId) {
        log.info("移动菜单: id={}, newParentId={}", id, newParentId);

        SysMenu menu = getById(id);

        // 检查不能移动到自己的子菜单下
        if (isDescendant(id, newParentId)) {
            throw new RuntimeException("不能移动到自己的子菜单下");
        }

        menu.setParentId(newParentId);
        menu.setUpdateTime(LocalDateTime.now());

        menuRepository.save(menu);

        log.info("菜单移动成功: id={}, newParentId={}", id, newParentId);
        return true;
    }

    /**
     * 检查是否为后代菜单
     *
     * @param ancestorId   祖先菜单ID
     * @param descendantId 后代菜单ID
     * @return 是否为后代
     */
    private boolean isDescendant(Long ancestorId, Long descendantId) {
        if (descendantId == null || descendantId <= 0) {
            return false;
        }

        List<SysMenu> children = menuRepository.findByParentId(ancestorId);
        for (SysMenu child : children) {
            if (child.getId().equals(descendantId)) {
                return true;
            }
            if (isDescendant(child.getId(), descendantId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 构建菜单查询条件
     *
     * @param queryRequest 查询请求
     * @return 查询条件
     */
    private Specification<SysMenu> buildMenuSpecification(MenuQueryRequest queryRequest) {
        return (root, query, cb) -> {
            List<jakarta.persistence.criteria.Predicate> predicates = new ArrayList<>();

            // 菜单名称模糊查询
            if (StringUtils.hasText(queryRequest.getName())) {
                predicates.add(cb.like(root.get("name"), "%" + queryRequest.getName() + "%"));
            }

            // 菜单编码模糊查询
            if (StringUtils.hasText(queryRequest.getCode())) {
                predicates.add(cb.like(root.get("code"), "%" + queryRequest.getCode() + "%"));
            }

            // 父菜单ID查询
            if (queryRequest.getParentId() != null) {
                predicates.add(cb.equal(root.get("parentId"), queryRequest.getParentId()));
            }

            // 菜单类型查询
            if (queryRequest.getType() != null) {
                predicates.add(cb.equal(root.get("type"), queryRequest.getType()));
            }

            // 状态查询
            if (queryRequest.getStatus() != null) {
                predicates.add(cb.equal(root.get("status"), queryRequest.getStatus()));
            }

            // 是否隐藏查询
            if (queryRequest.getHidden() != null) {
                predicates.add(cb.equal(root.get("hidden"), queryRequest.getHidden()));
            }

            // 权限标识模糊查询
            if (StringUtils.hasText(queryRequest.getPermission())) {
                predicates.add(cb.like(root.get("permission"), "%" + queryRequest.getPermission() + "%"));
            }

            // 创建时间范围查询
            if (StringUtils.hasText(queryRequest.getCreateTimeStart())) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("createTime"),
                        LocalDateTime.parse(queryRequest.getCreateTimeStart())));
            }
            if (StringUtils.hasText(queryRequest.getCreateTimeEnd())) {
                predicates.add(cb.lessThanOrEqualTo(root.get("createTime"),
                        LocalDateTime.parse(queryRequest.getCreateTimeEnd())));
            }

            return cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
        };
    }

    /**
     * 转换菜单实体为DTO
     *
     * @param menu 菜单实体
     * @return 菜单DTO
     */
    private MenuDTO convertToMenuDTO(SysMenu menu) {
        MenuDTO menuDTO = new MenuDTO();
        BeanUtils.copyProperties(menu, menuDTO);

        // 获取父菜单名称
        if (menu.getParentId() != null && menu.getParentId() > 0) {
            Optional<SysMenu> parentOpt = menuRepository.findById(menu.getParentId());
            if (parentOpt.isPresent()) {
                menuDTO.setParentName(parentOpt.get().getName());
            }
        }

        return menuDTO;
    }
}
